package deleteface.bank.jqsoft.cn.deleteface.rsa;



import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;

import javax.crypto.Cipher;

public class RsaHelper {
    public static KeyPair generateRSAKeyPair() {
        return generateRSAKeyPair(1024);
    }

    public static KeyPair generateRSAKeyPair(int keyLength) {
        try {
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA/ECB/PKCS1Padding");
            kpg.initialize(keyLength);
            return kpg.genKeyPair();
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    // 将公钥对象转换成为xml串
    public static String encodePublicKeyToXml(PublicKey key) {
        if (!RSAPublicKey.class.isInstance(key)) {
            return null;
        }
        RSAPublicKey pubKey = (RSAPublicKey) key;
        StringBuilder sb = new StringBuilder();

        sb.append("<RSAKeyValue>");
        sb.append("<Modulus>")
                .append(Base64Helper.encode(pubKey.getModulus().toByteArray()))
                .append("</Modulus>");
        sb.append("<Exponent>")
                .append(Base64Helper.encode(pubKey.getPublicExponent().toByteArray()))
                .append("</Exponent>");
        sb.append("</RSAKeyValue>");
        return sb.toString();
    }

    // 将公钥xml串转换为公钥对象
    public static PublicKey decodePublicKeyFromXml(String xml) {
        xml = xml.replaceAll("\r", "").replaceAll("\n", "");
        BigInteger modulus =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml,
                        "<Modulus>", "</Modulus>")));
        BigInteger publicExponent =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml,
                        "<Exponent>", "</Exponent>")));

        RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent);

        KeyFactory keyf;
        try {
            keyf = KeyFactory.getInstance("RSA");
            return keyf.generatePublic(rsaPubKey);
        } catch (Exception e) {
            return null;
        }
    }

    // 将私钥xml串转换成为私钥对象
    public static PrivateKey decodePrivateKeyFromXml(String xml) {
        xml = xml.replaceAll("\r", "").replaceAll("\n", "");
        BigInteger modulus =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml,
                        "<Modulus>", "</Modulus>")));
        BigInteger publicExponent =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml,
                        "<Exponent>", "</Exponent>")));
        BigInteger privateExponent =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml, "<D>",
                        "</D>")));
        BigInteger primeP =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml, "<P>",
                        "</P>")));
        BigInteger primeQ =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml, "<Q>",
                        "</Q>")));
        BigInteger primeExponentP =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml,
                        "<DP>", "</DP>")));
        BigInteger primeExponentQ =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml,
                        "<DQ>", "</DQ>")));
        BigInteger crtCoefficient =
                new BigInteger(1, Base64Helper.decode(StringUtils.getMiddleString(xml,
                        "<InverseQ>", "</InverseQ>")));

        RSAPrivateCrtKeySpec rsaPriKey =
                new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent, primeP,
                        primeQ, primeExponentP, primeExponentQ, crtCoefficient);

        KeyFactory keyf;
        try {
            keyf = KeyFactory.getInstance("RSA");
            return keyf.generatePrivate(rsaPriKey);
        } catch (Exception e) {
            return null;
        }
    }
    // 将私钥对象转换成为私钥串
    public static String encodePrivateKeyToXml(PrivateKey key) {
        if (!RSAPrivateCrtKey.class.isInstance(key)) {
            return null;
        }
        RSAPrivateCrtKey priKey = (RSAPrivateCrtKey) key;
        StringBuilder sb = new StringBuilder();

        sb.append("<RSAKeyValue>");
        sb.append("<Modulus>")
                .append(Base64Helper.encode(priKey.getModulus().toByteArray()))
                .append("</Modulus>");
        sb.append("<Exponent>")
                .append(Base64Helper.encode(priKey.getPublicExponent().toByteArray()))
                .append("</Exponent>");
        sb.append("<P>").append(Base64Helper.encode(priKey.getPrimeP().toByteArray()))
                .append("</P>");
        sb.append("<Q>").append(Base64Helper.encode(priKey.getPrimeQ().toByteArray()))
                .append("</Q>");
        sb.append("<DP>")
                .append(Base64Helper.encode(priKey.getPrimeExponentP().toByteArray()))
                .append("</DP>");
        sb.append("<DQ>")
                .append(Base64Helper.encode(priKey.getPrimeExponentQ().toByteArray()))
                .append("</DQ>");
        sb.append("<InverseQ>")
                .append(Base64Helper.encode(priKey.getCrtCoefficient().toByteArray()))
                .append("</InverseQ>");
        sb.append("<D>")
                .append(Base64Helper.encode(priKey.getPrivateExponent().toByteArray()))
                .append("</D>");
        sb.append("</RSAKeyValue>");
        return sb.toString();
    }


    public static byte[] encryptByPublicKey( byte[] data, PublicKey pubKey) throws Exception
    {

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0)
        {
            if ( inputLen - offSet > 117)
            {
                cache = cipher.doFinal( data, offSet, 117);
            }
            else
            {
                cache = cipher.doFinal( data, offSet, inputLen - offSet);
            }
            out.write( cache, 0, cache. length);
            i++;
            offSet = i * 117;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }
    // 公钥加密  返回byte数组
    public static byte[] encryptData(byte[] data, PublicKey pubKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            return cipher.doFinal(data);
        } catch (Exception e) {
            return null;
        }
    }
    // 私钥解密byte数组
    public static byte[] decryptData(byte[] encryptedData, PrivateKey priKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            return cipher.doFinal(encryptedData);
        } catch (Exception e) {
            return null;
        }
    }

    // 公钥加密字符串
    public static String encryptDataFromStr(String plainText, PublicKey pubKey) {
        try {
            byte[] dataByteArray = plainText.getBytes("UTF-8");

//            byte[] encryptedDataByteArray = RsaHelper.encryptData(dataByteArray, pubKey);
            String encryptRsa=TestRSA.encryptByPublicKey(dataByteArray, pubKey);
            return encryptRsa;

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return "";
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
}
